﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufBaseUtils.h"

class QWidget;
namespace gnuf {
    class DesktopArrangementArea;
    class ArrangementArea;
    class IsolatedArrangementArea;
    class DesktopArrangementArea;

    class GNUF_BASE_EXPORT ArrangementAreaEvent
    {
    public:
        enum class EType : std::uint16_t {
            eSearchDocking,
            eSetOpacity,
            eSetDisplayUnitActivity,
            eCloseIsolatedArrangementArea,
            eDesktopStatusChanged,
            eMasked,
            eSearchWindow,
            eWindowStateChanged,
            ePreferencesChanged,
            eScaleFactorChanged,
            eScenarioStarted,
            eScenarioEnded
        };
        void send();
        inline ArrangementArea * source() const { return m_source; }
        inline ArrangementAreaEvent::EType type() const { return m_type; }
        inline bool fromUpToDown() const { return m_fromUpToDown; }
        virtual bool accepted() const { return false; }
    protected:
        ArrangementAreaEvent(ArrangementArea *,
            ArrangementAreaEvent::EType, bool fromUpToDown);
        virtual ~ArrangementAreaEvent();

        // Give the derived class an opportunity to send this event.
        // The default implementation only sends this event to the 
        // source and its all child arrangment area(s).
        virtual void onSend();

        ArrangementArea * arrangementArea() const { return m_source; }
    private:
        ArrangementArea * m_source;
        const ArrangementAreaEvent::EType m_type;
        const bool m_fromUpToDown;
    };

    class SearchPotentialDockingArrangementAreaEvent final 
        : public ArrangementAreaEvent
    {
    public:
        SearchPotentialDockingArrangementAreaEvent(DesktopArrangementArea *,
            int globalX, int globalY, int tolerance);
        ~SearchPotentialDockingArrangementAreaEvent();

        void setArrangementArea(ArrangementArea *);
        inline ArrangementArea * arrangementArea() const { return m_arrangementArea; }
        inline bool ahead() const { return m_ahead; }
    protected:
        virtual bool accepted() const { return (nullptr != m_arrangementArea); }
    private:
        const int m_globalX, m_globalY, m_tolerance;
        ArrangementArea * m_arrangementArea;
        bool m_ahead;
    };

    class SetOpacityArrangementAreaEvent final 
        : public ArrangementAreaEvent
    {
    public:
        SetOpacityArrangementAreaEvent(ArrangementArea *,
            float opacity);
        ~SetOpacityArrangementAreaEvent();
        inline float opacity() const { return m_opacity; }
    private:
        const float m_opacity;
    };

    class SetDisplayUnitActivityArrangementAreaEvent final 
        : public ArrangementAreaEvent
    {
    public:
        SetDisplayUnitActivityArrangementAreaEvent(ArrangementArea *, bool activity);
        ~SetDisplayUnitActivityArrangementAreaEvent();
        bool canSpreadTo(const ArrangementArea *) const;
        bool activity() const { return m_activity; }
    private:
        const bool m_activity;
    };

    class CloseIsolatedArrangementAreaEvent final 
        : public ArrangementAreaEvent
    {
    public:
        CloseIsolatedArrangementAreaEvent(IsolatedArrangementArea *, bool wantToRetrieveBeforeClose = false);
        ~CloseIsolatedArrangementAreaEvent();
        bool wantToRetrieveBeforeClose() const { return m_wantToRetrieveBeforeClose; }
        void setApproved(bool approved) { m_approved = approved; }
        bool approved() const { return m_approved; }
    protected:
        virtual bool accepted() const { return (!m_approved); }
    private:
        const bool m_wantToRetrieveBeforeClose;
        bool m_approved;
    };

    class GNUF_BASE_EXPORT DesktopStatusChangedArrangementAreaEvent final 
        : public ArrangementAreaEvent
    {
    public:
        DesktopStatusChangedArrangementAreaEvent(DesktopArrangementArea *, bool operative);
        ~DesktopStatusChangedArrangementAreaEvent();
        bool isOperative() const { return m_operative; }
    private:
        bool m_operative;
    };

    class GNUF_BASE_EXPORT WindowStateChangedArrangmentAreaEvent final
        : public ArrangementAreaEvent
    {
    public:
        WindowStateChangedArrangmentAreaEvent(DesktopArrangementArea *, int);
        ~WindowStateChangedArrangmentAreaEvent();
        int states() const { return m_states; }
    private:
        int m_states;
    };

    class GNUF_BASE_EXPORT MaskedArrangementAreaEvent final 
        : public ArrangementAreaEvent
    {
    public:
        enum class EMasked : std::uint8_t { eNo, eYes, eOverall };
        MaskedArrangementAreaEvent(ArrangementArea *, MaskedArrangementAreaEvent::EMasked masked, const Color &);
        ~MaskedArrangementAreaEvent();
        bool isMasked()        const { return (              MaskedArrangementAreaEvent::EMasked::eNo      != m_masked); }
        bool isMaskedOverall() const { return (isMasked() && MaskedArrangementAreaEvent::EMasked::eOverall == m_masked); }
        const Color & color() const { return m_color; }
    private:
        const MaskedArrangementAreaEvent::EMasked m_masked = MaskedArrangementAreaEvent::EMasked::eNo; // unmasked
        const Color m_color;
    };

    class GNUF_BASE_EXPORT SearchWindowArrangementAreaEvent final
        : public ArrangementAreaEvent
    {
    public:
        SearchWindowArrangementAreaEvent(ArrangementArea *, const std::uint64_t & winId);
        ~SearchWindowArrangementAreaEvent();
        std::uint64_t winId() const { return m_winId; }
        bool isWinIdOf(const QWidget *) const;
        void setArrangementArea(const ArrangementArea * pArea) { m_pArrangementArea = pArea; }
        const ArrangementArea * arrangementArea() const { return m_pArrangementArea; }
    protected:
        virtual bool accepted() const override { return (nullptr != m_pArrangementArea); }
    private:
        const std::uint64_t     m_winId = 0; // invalid
        const ArrangementArea * m_pArrangementArea = nullptr;
    };

    class Preferences;
    class GNUF_BASE_EXPORT PreferencesChangedAreaEvent final
        : public ArrangementAreaEvent
    {
    public:
        PreferencesChangedAreaEvent(ArrangementArea *, const Preferences *);
        ~PreferencesChangedAreaEvent();
        const Preferences * preferences() const { return m_preferences; }
    protected:
        virtual void onSend() override;
    private:
        const Preferences * m_preferences;
    };

    class GNUF_BASE_EXPORT ScaleFactorChangedArrangementAreaEvent final
        : public ArrangementAreaEvent
    {
    public:
        ScaleFactorChangedArrangementAreaEvent(ArrangementArea *, const ScaleFactor &);
        ~ScaleFactorChangedArrangementAreaEvent();
        const ScaleFactor & scaleFactor() const { return m_scaleFactor; }
    private:
        const ScaleFactor m_scaleFactor;
    };

    class Scenario;
    class GNUF_BASE_EXPORT ScenarioChangedArrangementAreaEvent
        : public ArrangementAreaEvent
    {
    public:
        ScenarioChangedArrangementAreaEvent(ArrangementArea *, bool, const Scenario *);
        ~ScenarioChangedArrangementAreaEvent();
        const Scenario * scenario() const { return m_pScenario; }
        std::uint8_t scenarioType() const;
    private:
        const Scenario * m_pScenario;
    };
    class GNUF_BASE_EXPORT ScenarioStartedArrangementAreaEvent final
        : public ScenarioChangedArrangementAreaEvent
    {
    public:
        ScenarioStartedArrangementAreaEvent(ArrangementArea *, const Scenario *);
    };
    class GNUF_BASE_EXPORT ScenarioEndedArrangementAreaEvent final
        : public ScenarioChangedArrangementAreaEvent
    {
    public:
        ScenarioEndedArrangementAreaEvent(ArrangementArea *, const Scenario *);
    };
}
